{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 模型链\n",
    "### 链通常将大语言模型与提示结合在一起\n",
    "### 链可以一次性接收多个输入"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 大语言模型链"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_deepseek import ChatDeepSeek\n",
    "from langchain.prompts import ChatPromptTemplate\n",
    "from langchain.chains import LLMChain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from dotenv import load_dotenv\n",
    "import os\n",
    "load_dotenv()\n",
    "api_key = os.environ.get(\"DASHSCOPE_API_KEY\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "llm = ChatDeepSeek(api_key=api_key, base_url=\"https://api.deepseek.com/v1\",model=\"deepseek-chat\",temperature=0.0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 初始化提示模板"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt = ChatPromptTemplate.from_template(\"描述制造{product}的一个公司的最佳名称是什么？只需要输出公司名称就行，不需要其它内容。\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 构建大语言模型链"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "chain = LLMChain(llm=llm, prompt=prompt)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 运行大语言模型链"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'梦织纺'"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "product = \"大号床单套装\"\n",
    "chain.run(product)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'芯睿创想'"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.run(\"个人电脑\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 简单顺序链\n",
    "### 顺序链是按预定义顺序执行其链接的链。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import SimpleSequentialChain"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  创建两个子链"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "first_prompt = ChatPromptTemplate.from_template(\"描述制造{product}的一个公司的最佳名称是什么？只需要输出公司名称就行，不需要其它内容。\")\n",
    "chain_one = LLMChain(llm=llm, prompt = first_prompt)\n",
    "second_prompt = ChatPromptTemplate.from_template(\"写一个20字的描述对于下面这个公司：{company_name}\")\n",
    "chain_two = LLMChain(llm=llm, prompt = second_prompt)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 构建简单顺序链"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "overall_simple_chain = SimpleSequentialChain(chains=[chain_one, chain_two], verbose=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new SimpleSequentialChain chain...\u001b[0m\n",
      "\u001b[36;1m\u001b[1;3m梦织纺\u001b[0m\n",
      "\u001b[33;1m\u001b[1;3m梦织纺：以科技织造未来，用设计编织梦想的纺织创新企业。\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'梦织纺：以科技织造未来，用设计编织梦想的纺织创新企业。'"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "overall_simple_chain.run(\"大号床单套装\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 顺序链\n",
    "### 当只有一个输入和输出时，简单顺序链即可实现。当有多个输入或多个输出时，需要使用顺序链来实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import SequentialChain\n",
    "from langchain.chains import LLMChain\n",
    "from langchain.prompts import ChatPromptTemplate"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 创建四个子链"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "first_prompt = ChatPromptTemplate.from_template(\"把下面的评论review翻译成英文: \\n\\n{Review}\")\n",
    "chain_one = LLMChain(llm=llm, prompt=first_prompt, output_key=\"English_Review\")\n",
    "\n",
    "second_prompt = ChatPromptTemplate.from_template(\"请你用语句话总结下面的评论review:\\n\\n{English_Review}\")\n",
    "chain_two = LLMChain(llm=llm, prompt=second_prompt, output_key=\"summary\")\n",
    "\n",
    "third_prompt = ChatPromptTemplate.from_template(\"下面的评论review使用的是什么语言:\\n\\n{Review}\")\n",
    "chain_three = LLMChain(llm=llm, prompt=third_prompt, output_key = \"language\")\n",
    "\n",
    "fourth_prompt = ChatPromptTemplate.from_template(\"使用特定的语言对下面的总结写一个后续回复:\\n\\n总结:{summary}\\n\\n语言:{language}\")\n",
    "chain_four = LLMChain(llm=llm, prompt=fourth_prompt, output_key=\"followup_message\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 对四个子链进行组合"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "overall_chain = SequentialChain(\n",
    "    chains = [chain_one, chain_two, chain_three, chain_four],\n",
    "    input_variables = [\"Review\"],\n",
    "    output_variables = [\"English_Review\",\"summary\",\"language\",\"followup_message\"],\n",
    "    verbose = True\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_206710/4168341986.py:1: LangChainDeprecationWarning: The method `Chain.__call__` was deprecated in langchain 0.1.0 and will be removed in 1.0. Use :meth:`~invoke` instead.\n",
      "  overall_chain(\"Je trouve le goût médiocre. La mousse ne tient pas, c'est bizarre. \\\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new SequentialChain chain...\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'Review': \"Je trouve le goût médiocre. La mousse ne tient pas, c'est bizarre. J'achète les mêmes dans le commerce et le goût est bien meilleur...\\nVieux lot ou contrefaçon !?\",\n",
       " 'English_Review': \"I find the taste mediocre. The foam doesn't hold, it's strange. I buy the same ones in stores and the taste is much better...\\nOld batch or counterfeit!?\",\n",
       " 'summary': '味道平庸、泡沫不持久，疑似买到旧批或假货。',\n",
       " 'language': '这条评论使用的是**法语**。\\n\\n评论的中文翻译是：\\n“我觉得味道很一般。泡沫挂不住（不持久），这很奇怪。我在商店里买同样的东西，味道要好得多……\\n是陈年旧货还是假货！？”\\n\\n一些关键的法语词汇提示：\\n- **Je trouve** = 我觉得\\n- **goût** = 味道\\n- **médiocre** = 平庸的，一般的\\n- **mousse** = 泡沫（通常指啤酒、卡布奇诺咖啡或巧克力的泡沫）\\n- **achète** = 我购买\\n- **commerce** = 商店\\n- **Vieux lot** = 旧的批次\\n- **contrefaçon** = 假冒产品\\n\\n从内容（尤其是关于泡沫的持久性和对真伪的怀疑）来看，这很可能是一条对**啤酒**或**某种咖啡/巧克力饮品**的评论。',\n",
       " 'followup_message': \"Absolument, nous prenons votre commentaire très au sérieux.\\n\\nVeuillez nous excuser pour la qualité médiocre que vous avez constatée. La mousse qui ne tient pas et le goût anormal que vous décrivez ne correspondent absolument pas à la qualité de nos produits.\\n\\nNous vous remercions d'avoir signalé ce problème. Afin que nous puissions enquêter sur ce lot spécifique et vérifier s'il s'agit effectivement d'un **vieux lot** ou d'un problème d'origine, pourriez-vous s'il vous plaît nous envoyer les détails de fabrication (numéro de lot et date de péremption) qui se trouvent sur l'emballage à [adresse e-mail du service client] ?\\n\\nCela nous aidera grandement à identifier la source du problème et à garantir que cela ne se reproduise plus. Nous restons à votre entière disposition pour une solution.\\n\\nL'Équipe [Nom de la Marque]\"}"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "overall_chain(\"Je trouve le goût médiocre. La mousse ne tient pas, c'est bizarre. \\\n",
    "J'achète les mêmes dans le commerce et le goût est bien meilleur...\\nVieux lot ou \\\n",
    "contrefaçon !?\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 路由链"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 路由链：根据输入类型，选择将将输入传递给哪个子链\n",
    "- 路由器由两个部件组成：\n",
    "    1. 路由链：路由链本身，负责选择要调用的下一个链\n",
    "    2. destination_chains：路由链可以路由到的链。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains.router import MultiPromptChain\n",
    "from langchain.chains.router.llm_router import LLMRouterChain, RouterOutputParser\n",
    "from langchain.prompts import PromptTemplate"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 定义提示模板"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 第一个提示适合回答物理问题\n",
    "physics_template = \"\"\"\n",
    "你是一个非常聪明的物理专家。你擅长用一种简洁并且易于理解的方式去回答问题。\\\n",
    "当你不知道问题的答案时，你承认你不知道。\\\n",
    "这是一个问题：\\\n",
    "{input}\n",
    "\"\"\"\n",
    "# 第二个提示词适合回答数学问题\n",
    "math_template = \"\"\"\n",
    "你是一个非常优秀的数学家。\\\n",
    "你擅长回答数学问题。\\\n",
    "你之所以如此优秀，是因为你能够将棘手的问题分解为组成部分，\\\n",
    "回答组成部分，然后将它们组合在一起，回答更广泛的问题。\\\n",
    "这是一个问题：\\\n",
    "{input}\n",
    "\"\"\"\n",
    "\n",
    "# 第三个适合回答历史问题\n",
    "history_template = \"\"\"\n",
    "你是一位非常优秀的历史学家。\\\n",
    "你对一系列历史时期的人物、事件和背景有着极好的学识和理解，\\\n",
    "你有能力思考、反思、辩证、讨论和评估过去。\\\n",
    "你尊重历史证据，并由能力利用它来支持你的解释和判断。\\\n",
    "这是一个问题：\n",
    "{input}\n",
    "\"\"\"\n",
    "\n",
    "# 第四个适合回答计算机问题\n",
    "computerScience_template = \"\"\"\n",
    "你是一个成功的计算机科学专家。\\\n",
    "你有创造力、协作精神、前瞻思维、自信、解决问题的能力、对理论和算法的理解以及出色的沟通技巧。\\\n",
    "你非常擅长回答编程问题。\\\n",
    "你之所以如此优秀，是因为你知道如何通过机器来解决问题，\\\n",
    "并且你知道如何选择在时间复杂性和空间复杂性之间取得良好平衡的解决方案。\\\n",
    "这是一个输入：\\\n",
    "{input}\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 对提示模板进行命名和描述"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt_infos = [\n",
    "    {\n",
    "        \"名字\":\"物理学\",\n",
    "        \"描述\":\"擅长回答关于物理学的问题\",\n",
    "        \"提示模板\":physics_template\n",
    "    },\n",
    "    {\n",
    "        \"名字\":\"数学\",\n",
    "        \"描述\":\"擅长回答数学问题\",\n",
    "        \"提示模板\":math_template\n",
    "    },\n",
    "    {\n",
    "        \"名字\":\"历史\",\n",
    "        \"描述\":\"擅长回答历史问题\",\n",
    "        \"提示模板\":history_template\n",
    "    },\n",
    "    {\n",
    "        \"名字\":\"计算机科学\",\n",
    "        \"描述\":\"擅长回答计算机科学问题\",\n",
    "        \"提示模板\":computerScience_template\n",
    "    }\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在这里，我们需要一个**多提示链**。这是一种特定类型的提示链，用于在多个不同的提示模板之间进行路由。但是这只是路由的一种类型，我们也可以在任何类型的链之间进行路由。\n",
    "这里我们要实现的几个类式大模型路由器链。这个类本身使用语言模型来在不同的子链之间进行路由。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 基于提示模板创建相应目标链"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "destination_chains = {}\n",
    "for p_info in prompt_infos:\n",
    "    name = p_info[\"名字\"]\n",
    "    prompt_template = p_info[\"提示模板\"]\n",
    "    prompt = ChatPromptTemplate.from_template(template=prompt_template)\n",
    "    chain = LLMChain(llm=llm, prompt = prompt)\n",
    "    destination_chains[name] = chain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "物理学:擅长回答关于物理学的问题\n",
      "数学:擅长回答数学问题\n",
      "历史:擅长回答历史问题\n",
      "计算机科学:擅长回答计算机科学问题\n"
     ]
    }
   ],
   "source": [
    "destinations = [f\"{p['名字']}:{p['描述']}\" for p in prompt_infos]\n",
    "destinations_str = \"\\n\".join(destinations)\n",
    "print(destinations_str)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 创建默认目标链\n",
    "除了目标链之外，我们还需要一个默认目标链。这是当一个路由器无法决定使用哪个子链时调用的链。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "default_prompt = ChatPromptTemplate.from_template(\"{input}\")\n",
    "default_chain = LLMChain(llm=llm,prompt=default_prompt)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 定义不同链之间的路由模板"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 多提示路由模板\n",
    "MULTI_PROMPT_TEMPLATE = \"\"\"\n",
    "给语言模型一个原始输入，让其选择最合适输入的模型提示。\\\n",
    "系统将为您提供可用提示的名称以及最适合提示的描述。\\\n",
    "如果你认为修改原始输入最终会导致语言模型做出更好的相应，你也可以修改原始输入。\\\n",
    "\n",
    "<<格式>>\n",
    "返回一个带有JSON对象的markdown代码片段，该JSON对象的格式如下：\n",
    "\n",
    "\n",
    "```json\n",
    "{{{{\n",
    "    \"destination\":字符串  使用的提示名字或者使用 \"DEFAULT\"\n",
    "    \"next_inputs\":字符串  原始输入的改进版本\n",
    "}}}}\n",
    "```\n",
    "\n",
    "记住：\"destination\"必须是下面指定的候选提示名称之一，\\\n",
    "或者如果输入不太合适任何候选提示，则可以是 \"DEFAULT\"。\\\n",
    "记住：如果您认为不需要任何修改，则 \"next_inputs\"可以只是原始输入。\n",
    "\n",
    "<<候选提示>>\n",
    "{destinations}\n",
    "\n",
    "<<输入>>\n",
    "{{input}}\n",
    "\n",
    "<<输出（记住要包含```json）>>\n",
    "\n",
    "样例：\n",
    "<<输入>>\n",
    "\"什么是黑体辐射？\"\n",
    "<<输出>>\n",
    "```json\n",
    "{{{{\n",
    "    \"destination\": 字符串  使用的提示名称或者使用 \"DEFAULT\"\n",
    "    \"next_inputs\": 字符串  原始输入的改进版本\n",
    "}}}}\n",
    "```\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 构建路由链"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'\\n给语言模型一个原始输入，让其选择最合适输入的模型提示。系统将为您提供可用提示的名称以及最适合提示的描述。如果你认为修改原始输入最终会导致语言模型做出更好的相应，你也可以修改原始输入。\\n<<格式>>\\n返回一个带有JSON对象的markdown代码片段，该JSON对象的格式如下：\\n\\n\\n```json\\n{{\\n    \"destination\":字符串  使用的提示名字或者使用 \"DEFAULT\"\\n    \"next_inputs\":字符串  原始输入的改进版本\\n}}\\n```\\n\\n\\n记住：\"destination\"必须是下面指定的候选提示名称之一，或者如果输入不太合适任何候选提示，则可以是 \"DEFAULT\"。记住：如果您认为不需要任何修改，则 \"next_inputs\"可以只是原始输入。\\n\\n<<候选提示>>\\n物理学:擅长回答关于物理学的问题\\n数学:擅长回答数学问题\\n历史:擅长回答历史问题\\n计算机科学:擅长回答计算机科学问题\\n\\n<<输入>>\\n{input}\\n\\n<<输出（记住要包含```json）>>\\n\\n样例：\\n<<输入>>\\n\"什么是黑体辐射？\"\\n<<输出>>\\n```json\\n{{\\n    \"destination\": 字符串  使用的提示名称或者使用 \"DEFAULT\"\\n    \"next_inputs\": 字符串  原始输入的改进版本\\n}}\\n```\\n'"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "router_template = MULTI_PROMPT_TEMPLATE.format(destinations=destinations_str)\n",
    "router_template"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [],
   "source": [
    "router_ptompt = PromptTemplate(\n",
    "    template=router_template,\n",
    "    input_variables=[\"input\"],\n",
    "    output_parser=RouterOutputParser()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "PromptTemplate(input_variables=['input'], input_types={}, output_parser=RouterOutputParser(), partial_variables={}, template='\\n给语言模型一个原始输入，让其选择最合适输入的模型提示。系统将为您提供可用提示的名称以及最适合提示的描述。如果你认为修改原始输入最终会导致语言模型做出更好的相应，你也可以修改原始输入。\\n<<格式>>\\n返回一个带有JSON对象的markdown代码片段，该JSON对象的格式如下：\\n\\n\\n```json\\n{{\\n    \"destination\":字符串  使用的提示名字或者使用 \"DEFAULT\"\\n    \"next_inputs\":字符串  原始输入的改进版本\\n}}\\n```\\n\\n\\n记住：\"destination\"必须是下面指定的候选提示名称之一，或者如果输入不太合适任何候选提示，则可以是 \"DEFAULT\"。记住：如果您认为不需要任何修改，则 \"next_inputs\"可以只是原始输入。\\n\\n<<候选提示>>\\n物理学:擅长回答关于物理学的问题\\n数学:擅长回答数学问题\\n历史:擅长回答历史问题\\n计算机科学:擅长回答计算机科学问题\\n\\n<<输入>>\\n{input}\\n\\n<<输出（记住要包含```json）>>\\n\\n样例：\\n<<输入>>\\n\"什么是黑体辐射？\"\\n<<输出>>\\n```json\\n{{\\n    \"destination\": 字符串  使用的提示名称或者使用 \"DEFAULT\"\\n    \"next_inputs\": 字符串  原始输入的改进版本\\n}}\\n```\\n')"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "router_ptompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [],
   "source": [
    "router_chain = LLMRouterChain.from_llm(llm, router_ptompt)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 创建整体链路"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 多提示链\n",
    "chain = MultiPromptChain(\n",
    "    router_chain=router_chain,# 路由链\n",
    "    destination_chains=destination_chains,# 目标链路\n",
    "    default_chain=default_chain,# 默认链路\n",
    "    verbose=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 进行提问"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new MultiPromptChain chain...\u001b[0m\n",
      "物理学: {'input': '什么是黑体辐射？'}\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'当然！让我们用一种简单的方式来理解黑体辐射。\\n\\n**黑体辐射**是指一个“理想化”的物体（称为**黑体**）被加热时发出的电磁辐射。\\n\\n你可以把它想象成一个**完美的吸收体和辐射体**：\\n1.  **完美的吸收体**：它能 100% 吸收所有照射到它身上的光（任何波长、任何方向的光），完全不反射，所以看起来是“黑色”的——这就是“黑体”名字的由来。\\n2.  **完美的辐射体**：当它被加热时，它也能发出所有波长的光，其发出的辐射**只取决于它的温度**，而与它本身的材质无关。\\n\\n**一个生活中的例子：**\\n一根铁棒被加热时，它的颜色会随着温度升高而改变：\\n- 刚开始是暗红色\\n- 然后变成亮红色\\n- 接着是黄色\\n- 最后会发出蓝白色的光\\n\\n这个颜色（即辐射的波长分布）的变化只由温度决定，这就是黑体辐射的直观体现。太阳、白炽灯泡的灯丝，都可以近似看作黑体。\\n\\n**为什么它如此重要？**\\n在19世纪末，经典物理理论（瑞利-金斯定律）无法解释黑体辐射的实验数据——在高频（紫外）区域，理论预测能量会趋于无穷大，这与实验严重不符。这个难题被称为“**紫外灾难**”。\\n\\n正是为了解决这个矛盾，**马克斯·普朗克**在1900年提出了一个革命性的假设：能量不是连续变化的，而是以一份份最小的单位“**量子**”来发射或吸收的。\\n\\n这个假设成功地推导出了与实验完美吻合的黑体辐射公式，并**直接催生了量子力学的诞生**。因此，黑体辐射是物理学从经典理论走向量子理论的关键转折点。\\n\\n**总结一下：**\\n**黑体辐射是一个只由其温度决定的理想热辐射。研究它的规律导致了量子理论的诞生，彻底改变了我们对微观世界的认识。**'"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.run(\"什么是黑体辐射？\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new MultiPromptChain chain...\u001b[0m\n",
      "数学: {'input': '2+2等于多少？'}\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'我们来逐步分析这个问题：\\n\\n**问题：2 + 2 等于多少？**\\n\\n**步骤分解：**\\n1. 这是一个基本的加法运算。\\n2. 数字“2”表示一个数量（例如，两个物体）。\\n3. 加法操作“+”表示将两个数量合并在一起。\\n4. 因此，将两个“2”合并，得到总数量。\\n\\n**计算：**\\n- 2 + 2 = 4\\n\\n**结论：**\\n2 + 2 等于 4。\\n\\n**最终答案：**\\n\\\\boxed{4}'"
      ]
     },
     "execution_count": 59,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.run(\"2+2等于多少？\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new MultiPromptChain chain...\u001b[0m\n",
      "None: {'input': '为什么我们身体里的细胞都包含DNA？'}\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'这是一个非常好的问题！它触及了生命最基本的核心原理。简单来说，我们身体里的每一个细胞都包含完整的DNA，是因为**DNA就像一套详尽无比的“生命指令总手册”或“建筑蓝图”**。\\n\\n这套蓝图包含了构建和运行你整个身体所需的全部信息。以下是详细的原因和解释：\\n\\n### 1. DNA的核心作用：信息的存储中心\\nDNA（脱氧核糖核酸）是一种分子，它以一种叫做“基因”的编码形式，存储了构建所有蛋白质的指令。而蛋白质是生命的“工作者”，它们：\\n*   **构建结构**：如胶原蛋白构成皮肤，角蛋白构成头发指甲。\\n*   **执行功能**：如血红蛋白运输氧气，消化酶分解食物。\\n*   **调控过程**：如激素和受体控制新陈代谢和生长发育。\\n\\n没有DNA，细胞就无法知道该制造哪些蛋白质，生命也就无法维持。\\n\\n### 2. 为什么“每个”细胞都需要“完整”的DNA？\\n这似乎有点浪费：一个肝细胞明明不需要如何制造视网膜色素的指令，为什么它也要拥有这些基因呢？这主要有两个关键原因：\\n\\n**原因一：发育起源（所有细胞都来自同一个起点）**\\n你的生命始于一个细胞——受精卵。这个细胞包含了你从父母那里继承来的**一整套完整的DNA**。当它开始分裂、分化（变成皮肤细胞、脑细胞、血细胞等）时，它会通过一个非常精确的过程（**有丝分裂**）将这套完整的DNA复制并平均分配到两个子细胞中。如此往复，每一个新产生的细胞都自然获得了一份完整的基因组拷贝。\\n\\n**原因二：细胞分化是“选择性表达”，而非“丢弃信息”**\\n细胞虽然拥有全套DNA，但并不会使用所有的指令。它们会通过一个精妙的调控系统，**“打开”（表达）自己职责所需的基因，同时“关闭”其他无关基因**。\\n\\n*   **举例**：\\n    *   在胰腺的**胰岛细胞**中，制造胰岛素的基因被打开，而其他基因（如制造角蛋白的基因）则被关闭。\\n    *   在**视网膜细胞**中，制造感光色素的基因被打开，而制造消化酶的基因则被关闭。\\n\\n这个过程就像一本巨大的百科全书（完整的DNA），不同专业的工程师（不同的细胞）只查阅与他们项目相关的章节，而忽略其他部分。但他们仍然需要拥有整本书，因为：\\n1.  **灵活性**：在某些情况下，细胞可能需要应对新的挑战，拥有全套指令提供了潜在的适应性。\\n2.  **完整性**：丢弃部分DNA是一个高风险且不可逆的过程，容易出错。保持DNA的完整性更安全可靠。\\n3.  **修复能力**：拥有完整的备份有助于修复受损的DNA片段。\\n\\n### 3. 重要的例外\\n有两个重要的例外证明了上述规则：\\n*   **成熟的红细胞**：为了使自身能容纳更多携带氧气的血红蛋白，它们在成熟过程中会**将细胞核和整个DNA排出体外**。因此，成熟的红细胞没有DNA，但代价是它们寿命很短（约120天），且无法自行分裂或修复。\\n*   **血小板**：它们是细胞的碎片，而不是完整的细胞，因此也没有细胞核和DNA。\\n\\n### 总结\\n我们可以用一个比喻来总结：\\n\\n**你的身体就像一个庞大的国家，DNA就是国家的《宪法和所有法律法规及工程手册全集》。每一个城市（细胞）都拥有一套完整的副本。**\\n*   **消防局**（肌肉细胞）主要查阅关于消防和救灾的章节（表达肌肉蛋白基因）。\\n*   **图书馆**（神经细胞）主要查阅关于信息管理和存储的章节（表达神经递质基因）。\\n*   **面包店**（唾液腺细胞）主要查阅关于食品生产的章节（表达消化酶基因）。\\n\\n虽然每个部门只使用与其职能相关的部分，但拥有完整的法律文本确保了国家的统一性、稳定性和每个部门在需要时都能找到最高权威的指导。\\n\\n因此，我们身体里的每个细胞都包含完整的DNA，是因为这是最安全、最有效、最能保证生命从单个细胞发育成复杂个体并维持其功能的方式。'"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.run(\"为什么我们身体里的细胞都包含DNA？\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
